Skip to content

fix(compliance): set aside unadvertised request signing in Strict Spec - #8952

Merged
bokelley merged 1 commit into
adcontextprotocol:mainfrom
Synaeve:fix/8534-strict-spec-applicability
Nov 13, 2026
Merged

bokelley merged 1 commit into
adcontextprotocol:mainfrom
Synaeve:fix/8534-strict-spec-applicability

Conversation

@Synaeve

@Synaeve Synaeve commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Refs #8534

No Strict Spec verdict changes today. webhook-emission, webhook-receiver-envelope and idempotency (hosted runner and test-kit gaps) keep every hosted agent partial. 3.1 media-buy sellers also keep their declined-capability bundles until the SDK change below ships. This PR removes one universal blocker for every agent that does not sign requests, and makes the saved run list the bundles that block Strict.

Problem

Strict Spec (strict-complete-bundles in server/src/services/verification-profile-assessment.ts) counts every relevant partial or untested bundle as incomplete. #8534 lists 19 such bundles for a media-buy 3.1 seller whose executed checks all pass. Most of them are now covered elsewhere:

#8534 bundles Covered by
signals, collection-list, property-list and content-standards storyboards (storyboards_missing_tools) #8824 (hosted, released bundles). For error-compliance-signals and schema-validation-signals only, #8601 also adds root supported_protocols gates in source (future releases), which adcp-client#3520 (in the pinned @adcp/sdk 17.0.0-beta.21) evaluates before missing tools. The four pagination storyboards are covered by #8824 only
wholesale-feed-* and the 31 "never selected" media-buy scenarios Since adcp-client#3520 every root-gated storyboard is kept for the runner (the 3.1.29 media-buy bundle has exactly 31), and the runner sets these aside as capability_unsupported. adcp-client#2960 grades that not_applicable only from AdCP 3.2 (CAPABILITY_ROLLUP_MIN_ADCP_VERSION, unchanged on adcp-client main 10f6fcd51 and in 17.0.0-beta.22 and beta.23). Fixing 3.1.24+ belongs in the SDK; see Follow-ups
signed-requests Not covered. This PR
webhook-emission, webhook-receiver-envelope, idempotency Runner and test-kit gaps. They stay incomplete, as the maintainer brief requires

signed_requests "runs for any agent advertising request_signing.supported: true". For other agents, "absence of advertisement is not a failure" (signed-requests.yaml, every release since 3.0.1). The runner reports this as requirement_unmet:request_signer (skip_reason: not_applicable, requirement: request_signer). The SDK grades it partial on every release, so every agent that does not sign requests has an incomplete universal bundle.

Changes

server/src/services/verification-profile-request-signing.ts (new)

requestSigningNotAdvertised(result) is true only when all of these hold; the assessment then sets signed_requests aside:

  • the agent's raw capabilities are present and do not declare request_signing.supported: true;
  • the storyboard was executed and is not in storyboards_missing_tools;
  • no failure or storyboard-assertion-failed observation names it;
  • its only projected result is the runner's single unmet-signer row, with no validations.

Any other unmet requirement, test-kit gap or fixture gap stays a coverage gap (runner-output-contract.yaml > skip_result).

server/src/services/verification-profile-assessment.ts

server/src/services/verification-profile-tool-obligations.ts

Exports record() for reuse.

server/src/schemas/registry.ts, static/openapi/registry.yaml

Document incomplete_bundle_ids and the widened not_applicable_universal_bundle_ids. The OpenAPI file is regenerated.

docs/building/verification/how-grading-works.mdx

Adds one "Pass vs partial coverage" row for signed_requests, noting that other unmet runner requirements still count as incomplete. The next row now excepts both the controller and request_signer rows.

Tests

server/tests/unit/verification-profile-request-signing.test.ts models the #8534 agent: media-buy, sales-non-guaranteed, supported_protocols: ["media_buy"], no wholesale feed, request signing, audience targeting or reach metrics. Gate rows come from the SDK's own runStoryboard (with a client that fails if called) and its track projection. Bundle statuses come from buildComplianceBundleResults on the real 3.1.29 and 3.2.10 catalogs.

  • 3.1.29 issue run: signed-requests and fix(compliance): stop Strict counting undeclared universal surfaces as incomplete (#8527) #8824's six bundles are set aside. incomplete_bundle_ids lists the five wholesale-feed-* bundles, webhook-emission, webhook-receiver-envelope, idempotency and protocol:media-buy.
  • 3.2.10 run with the runner gaps closed: Strict passes. The SDK sets aside the declined capability gates; this PR sets aside signed-requests.
  • Fail-closed guards, each checked against the positive case:
    • the agent advertises signing;
    • raw capabilities are missing;
    • a different requirement;
    • the storyboard is also listed as missing tools;
    • a recorded failure;
    • a storyboard-scoped assertion failure;
    • a step ran beside the row;
    • validations on the row;
    • the storyboard was not executed;
    • an unmet-signer row on another storyboard.
  • All 12 tests fail without the assessment change. Removing any single guard fails its test.
  • Related suites: 17 files, 298 tests pass. The server typecheck, link-compliance-symbols --check and the changeset scope check pass. Committed with HUSKY=0; CI is authoritative for the full suite.

Changeset

None: server and non-normative docs only. The protocol-scope check passes.

Out of scope / follow-ups

🤖 Generated with Claude Code

grading
- treat signed_requests as not applicable when the runner set it aside
  only because the agent does not advertise request_signing.supported
- keep runner limitations, test-kit gaps and failures incomplete
- list incomplete bundle ids in the Strict Spec evidence

docs
- add the signed_requests row to how grading works
@mintlify

mintlify Bot commented Nov 12, 2026

Copy link
Copy Markdown

Preview approval required

This pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit 47d0b4f.

Approve preview

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Approve

Approve — clean server-only Strict Spec change.

No Critical/High/Medium findings reported. Verified the key non-escalation conditions:

  • static/schemas/source/** untouched — no schema↔docs coherence concern; OpenAPI regenerated to match the Zod registry and the docs row is coherent with the schema description.
  • Changeset correctly omitted (server logic + non-normative docs; scope check passes).
  • Not a breaking-class protocol change — signed_requests is set aside when an agent doesn't advertise request_signing.supported: true, and a new incomplete_bundle_ids evidence field is additive server-side behavior; the hard breaking-class gate does not apply.
  • gated_paths: false, so row 2 does not fire despite review_decision: REVIEW_REQUIRED.
  • high_risk: false, no author team gate.

The requestSigningNotAdvertised path is fail-closed on every guard and onlyUnmetSignerRow acts as a real suspender so a malformed capability shape can't wrongly pass. New test coverage (verification-profile-request-signing.test.ts, +391 net) exercises the throwing Proxy client and the fail-closed guard matrix. Rows 1–8 do not match; falls through to row 9.

@bokelley
bokelley merged commit e55bf92 into adcontextprotocol:main Nov 13, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants